/**
 * GameData.java
 *
 * Roslan's Remake of MOO in 3D using Ardor3D
 * (C) 2011 Roslan Amir. All rights reserved.
 */

package com.roslan.games.moo3d;

import java.io.Serializable;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;

import com.ardor3d.math.ColorRGBA;
import com.ardor3d.math.Vector3;
import com.ardor3d.math.type.ReadOnlyColorRGBA;
import com.roslan.games.moo3d.data.Race;
import com.roslan.games.moo3d.events.Event;
import com.roslan.games.moo3d.spatial.FleetNode;
import com.roslan.games.moo3d.spatial.StarNode;
import com.roslan.games.moo3d.spatial.StarNodeList;
import com.roslan.games.moo3d.utils.HexGridUtils;

/**
 * Comments go here.
 * 
 * @author Roslan Amir
 * @version 1.0 - Jan 4, 2011
 */
public class GameData implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

//	/**
//	 * The color ROYAL_BLUE (#2B60DE)
//	 */
//	public static final ReadOnlyColorRGBA COLOR_ROYAL_BLUE = new ColorRGBA(43f / 255f, 96f / 255f, 222f / 255f, 1f);

//	/**
//	 * The color LIME_GREEN (#41A317)
//	 */
//	public static final ReadOnlyColorRGBA COLOR_LIME_GREEN = new ColorRGBA(65f / 255f, 163f / 255f, 23f / 255f, 1f);

//	/**
//	 * The color DARK_VIOLET (#842DCE)
//	 */
//	public static final ReadOnlyColorRGBA COLOR_DARK_VIOLET = new ColorRGBA(132f / 255f, 45f / 255f, 206f / 255f, 1f);

//	/**
//	 * The color RED_1 (#F62217)
//	 */
//	public static final ReadOnlyColorRGBA COLOR_RED_1 = new ColorRGBA(246f / 255f, 34f / 255f, 23f / 255f, 1f);

//	/**
//	 * The color YELLOW_1 (#FFFC17)
//	 */
//	public static final ReadOnlyColorRGBA COLOR_YELLOW_1 = new ColorRGBA(1f, 252f / 255f, 23f / 255f, 1f);

//	/**
//	 * The color PURPLE (#8E35EF)
//	 */
//	public static final ReadOnlyColorRGBA COLOR_PURPLE = new ColorRGBA(142f / 255f, 53f / 255f, 239f / 255f, 1f);

//	/**
//	 * The color VIOLET (#8D38C9)
//	 */
//	public static final ReadOnlyColorRGBA COLOR_VIOLET = new ColorRGBA(141f / 255f, 56f / 255f, 201f / 255f, 1f);

//	/**
//	 * The color ORANGE (#FF8040)
//	 */
//	public static final ReadOnlyColorRGBA COLOR_ORANGE = new ColorRGBA(1f, 128f / 255f, 64f / 255f, 1f);

//	/**
//	 * The color DEEP_PINK(#F52887)
//	 */
//	public static final ReadOnlyColorRGBA COLOR_DEEP_PINK = new ColorRGBA(245f / 255f, 40f / 255f, 135f / 255f, 1f);

	/**
	 * The color DARK_YELLOW
	 */
	public static final ReadOnlyColorRGBA COLOR_DARK_YELLOW = new ColorRGBA(0.5f, 0.5f, 0f, 1f);

	/**
	 * The color DARK_GREEN
	 */
	public static final ReadOnlyColorRGBA COLOR_DARK_GREEN = new ColorRGBA(0f, 0.5f, 0f, 1f);

	/**
	 * The color DARK_RED
	 */
	public static final ReadOnlyColorRGBA COLOR_DARK_RED = new ColorRGBA(0.5f, 0f, 0f, 1f);

	/**
	 * The color DARK_WHITE
	 */
	public static final ReadOnlyColorRGBA COLOR_DARK_WHITE = new ColorRGBA(0.5f, 0.5f, 0.5f, 1f);

	/**
	 * The color DARK_BLUE
	 */
	public static final ReadOnlyColorRGBA COLOR_DARK_BLUE = new ColorRGBA(0f, 0f, 0.5f, 1f);

	/**
	 * The color DARK_MAGENTA
	 */
	public static final ReadOnlyColorRGBA COLOR_DARK_MAGENTA = new ColorRGBA(0.5f, 0f, 0.5f, 1f);

	/**
	 * The color CHOCOLATE(#C85A17)
	 */
	public static final ReadOnlyColorRGBA COLOR_CHOCOLATE = new ColorRGBA(200f / 255f, 90f / 255f, 23f / 255f, 1f);

	/**
	 * The color MOO2_RED (182,0,0)
	 */
	public static final ReadOnlyColorRGBA COLOR_MOO2_RED = new ColorRGBA(182f / 255f, 0f, 0f, 1f);

	/**
	 * The color MOO2_YELLOW (215,203,0)
	 */
	public static final ReadOnlyColorRGBA COLOR_MOO2_YELLOW = new ColorRGBA(215f / 255f, 203f / 255f, 0f, 1f);

	/**
	 * The color MOO2_GREEN (0,174,65)
	 */
	public static final ReadOnlyColorRGBA COLOR_MOO2_GREEN = new ColorRGBA(0f, 174f / 255f, 65f / 255f, 1f);

	/**
	 * The color MOO2_GREY (146,154,162)
	 */
	public static final ReadOnlyColorRGBA COLOR_MOO2_GREY = new ColorRGBA(146f / 255f, 154f / 255f, 162f / 255f, 1f);

	/**
	 * The color MOO2_BLUE (48,0,207)
	 */
	public static final ReadOnlyColorRGBA COLOR_MOO2_BLUE = new ColorRGBA(48f / 255f, 0f, 207f / 255f, 1f);

	/**
	 * The color MOO2_BROWN (174,117,81)
	 */
	public static final ReadOnlyColorRGBA COLOR_MOO2_BROWN = new ColorRGBA(174f / 255f, 117f / 255f, 81f / 255f, 1f);

	/**
	 * The color MOO2_PURPLE (162,28,207)
	 */
	public static final ReadOnlyColorRGBA COLOR_MOO2_PURPLE = new ColorRGBA(162f / 255f, 28f / 255f, 207f / 255f, 1f);

	/**
	 * The color MOO2_ORANGE (235,146,36)
	 */
	public static final ReadOnlyColorRGBA COLOR_MOO2_ORANGE = new ColorRGBA(235f / 255f, 146f / 255f, 36f / 255f, 1f);

	/**
	 * The different colors for the stars - within scanner range.
	 */
	public final static ReadOnlyColorRGBA[] STAR_COLORS_BRIGHT = { 
		ColorRGBA.YELLOW, 
		ColorRGBA.GREEN, 
		ColorRGBA.RED, 
		ColorRGBA.WHITE, 
		ColorRGBA.BLUE,
		ColorRGBA.MAGENTA };

	/**
	 * The different colors for the stars - outside scanner range.
	 */
	public final static ReadOnlyColorRGBA[] STAR_COLORS_DARK = {
		COLOR_DARK_YELLOW,
		COLOR_DARK_GREEN,
		COLOR_DARK_RED,
		COLOR_DARK_WHITE,
		COLOR_DARK_BLUE,
		COLOR_DARK_MAGENTA };

	/**
	 * The list of player race banner colors.
	 */
	public static final ReadOnlyColorRGBA[] BANNER_COLORS = {
		COLOR_MOO2_RED,
		COLOR_MOO2_YELLOW,
		COLOR_MOO2_GREEN,
		COLOR_MOO2_GREY,
		COLOR_MOO2_BLUE,
		COLOR_MOO2_BROWN,
		COLOR_MOO2_PURPLE,
		COLOR_MOO2_ORANGE };

	/**
	 * The number of colors assignable to the races.
	 */
	public static final int TOTAL_NO_OF_BANNERS = BANNER_COLORS.length;

	/**
	 * Game actions.
	 */
	public enum Actions {
		NONE, 
		SHOW_MAIN_MENU, 
		SHOW_LOAD_GAME_MENU, 
		SHOW_NEW_GAME_MENU, 
		SHOW_OPTIONS_MENU, 
		SHOW_CHOOSE_RACE_MENU, 
		SHOW_CHOOSE_BANNER_MENU, 
		SHOW_CHOOSE_LEADER_NAME_MENU, 
		SHOW_CHOOSE_STAR_NAME_MENU, 
		CONTINUE_GAME, START_GAME, 
		CAM_LEFT, 
		CAM_RIGHT, 
		CAM_DOWN, 
		CAM_UP,
		TOGGLE_GRID, 
		TILE_CLICKED,
		CENTER_ON_STAR, 
		CENTER_ON_FLEET, 
		STAR_PICKED, 
		SHOW_PREV_STAR, 
		SHOW_NEXT_STAR,
		SHOW_PREV_COLONY, 
		SHOW_NEXT_COLONY, 
		FLEET_PICKED, 
		SHOW_PREV_FLEET, 
		SHOW_NEXT_FLEET, 
		DESTINATION_PICKED, 
		START_COLONY_PRODUCTION, 
		NEXT_COLONY_PRODUCTION, 
		START_FLEET_MOVEMENT, 
		MOVE_NEXT_FLEET, 
		MOVE_CURRENT_FLEET, 
		SHOW_EVENT, 
		SHOW_EXPLORE_EVENT,
		SHOW_COLONIZE_EVENT,
		SHOW_COLONIZED_INFO,
		HIDE_COLONIZED_INFO,
		EXIT_GAME,
	}

	/**
	 * Game states.
	 */
	public enum GameStates {
		IN_MENU,
		IN_STAR_INFO,
		IN_FLEET_INFO,
		IN_COLONY_PRODUCTION,
		IN_FLEET_MOVEMENT,
		IN_SHOW_EVENT,
	}

	/*
	 * The renderer parameters.
	 */
	public static int screenWidth;
	public static int screenHeight;
	public static int screenColorDepth;
	public static int screenFrequency;
	public static boolean screenFullScreen;

	/**
	 * Returns the singleton instance of this class.
	 * 
	 * @return the singleton instance of this class
	 */
	public static GameData getInstance() {
		if (instance == null) {
			instance = new GameData();
		}
		return instance;
	}

	/**
	 * The singleton instance of this class.
	 */
	private static GameData instance;

	/**
	 * Default no-arg constructor.
	 */
	private GameData() {
	}

	/**
	 * The list of stars in the galaxy belonging to each race in the game.
	 */
//	private final static HashMap<String, StarNodeList> starHashMap = new HashMap<String, StarNodeList>(7, 1);

	/**
	 * The lists of fleets belonging to each race in the game.
	 */
	private final static HashMap<Race, ArrayList<FleetNode>> fleetHashMap = new HashMap<Race, ArrayList<FleetNode>>(6, 1);

	/**
	 * The list of fleets orbiting a star.
	 */
	private final static HashMap<StarNode, ArrayList<FleetNode>> orbitingHashMap = new HashMap<StarNode, ArrayList<FleetNode>>();

	/**
	 * The list of fleets departing from a star.
	 */
	private final static HashMap<StarNode, ArrayList<FleetNode>> departingHashMap = new HashMap<StarNode, ArrayList<FleetNode>>();

	/**
	 * The fleet discard list. Discarded fleets after merging are kept here for disposal later.
	 */
	private static final ArrayList<FleetNode> discardList = new ArrayList<FleetNode>();

	/**
	 * Current game year - starts at 2400.
	 */
	public int gameYear;

	/**
	 * Current game month - expressed as a fraction of a year (.0-.9).
	 */
	public int gameMonth;

	/**
	 * Current game turn.
	 */
	public int gameTurn;

	/**
	 * The galaxy size index: 0=Small, 1=Medium, 2=large, 3=Huge
	 */
	public int galaxySizeIndex;

	/**
	 * The difficulty index: 0=Easy, 1=Simple, 2=Average, 3=hard, 5=Impossible
	 */
	public int difficultyIndex;

	/**
	 * The number of races for this game. Default is 2 (player race + one AI race)
	 */
	public int raceCount = 2;

	/**
	 * The index into the the various Race arrays representing the selected player race.
	 */
	public int playerRaceIndex;

	/**
	 * The index into the the Race banner arrays representing the selected player race's banner.
	 */
	public int playerBannerIndex;

	/**
	 * 
	 */
	public String playerLeaderName;

	/**
	 * The name given to the player home world.
	 */
	public String homeStarName;

	/**
	 * Currently selected save file slot (0-5)
	 */
	public int saveFileIndex;

	/**
	 * Name of the currently selected save game file
	 */
	public String saveFileName;

	/**
	 * 
	 */
	public int galaxyWidth;

	/**
	 * 
	 */
	public int galaxyHeight;

	/**
	 * 
	 */
	public int starCount;

	/**
	 * The array of player race plus the AI races.
	 */
	public Race[] races;

	/**
	 * The player race.
	 */
	public Race playerRace;

	/**
	 * The star list.
	 */
	public final StarNodeList starList = new StarNodeList(24);

	/**
	 * The player fleet list.
	 */
	public ArrayList<FleetNode> playerFleetList;

	/**
	 * The reference to the player's home star node.
	 */
	public StarNode playerHomeStarNode;

	/**
	 * The reference to the currently selected star or colony node.
	 */
	public transient StarNode currentStarNode;

	/**
	 * The reference to the currently selected fleet node.
	 */
	public transient FleetNode currentFleetNode;

	/**
	 * The reference to the selected star or colony node that is meant to be a fleet destination. (Working variable)
	 */
	public transient StarNode currentDestination;

	/**
	 * Current user interface action.
	 */
	public transient Actions action = Actions.NONE;

	/**
	 * Current game state.
	 */
	public transient GameStates gameState = GameStates.IN_MENU;

	/**
	 * The event queue. All events generated will be added to this queue before processing.
	 */
	public final Deque<Event> eventQueue = new ArrayDeque<Event>();

	/**
	 * The Vector whose tile was clicked.
	 */
	public Vector3 clickedVector;

	/**
	 * The minimum X coordinate the camera can scroll to.
	 */
	public double minWorldX;

	/**
	 * The maximum X coordinate the camera can scroll to.
	 */
	public double maxWorldX;

	/**
	 * The minimum Y coordinate the camera can scroll to.
	 */
	public double minWorldY;

	/**
	 * The maximum Y coordinate the camera can scroll to.
	 */
	public double maxWorldY;

	/**
	 * Set the scoll limits based on the galaxy size.
	 */
	public void setScrollLimits() {
		double[] tuple = HexGridUtils.getHexWorldOrigin(0.0, 0.0, null);
		this.minWorldY = tuple[1];
		HexGridUtils.getHexWorldOrigin(this.galaxyWidth - 1, 0.0, tuple);
		this.maxWorldX = tuple[0];
		HexGridUtils.getHexWorldOrigin(0.0, this.galaxyHeight - 1, tuple);
		this.minWorldX = tuple[0];
		HexGridUtils.getHexWorldOrigin(this.galaxyWidth - 1, this.galaxyHeight - 1, tuple);
		this.maxWorldY = tuple[1];
	}

//	/**
//	 * Returns the list of stars (colonies) belonging to the specified race.
//	 * 
//	 * @param raceName - the race who owns the stars
//	 * @return the star list for the race
//	 */
//	public static StarNodeList getStarList(String raceName) {
//		StarNodeList list = starHashMap.get(raceName);
//		if (list == null) {
//			list = new StarNodeList(4);
//			starHashMap.put(raceName, list);
//		}
//		return list;
//	}

	/**
	 * Returns the list of fleets belonging to the specified race.
	 * 
	 * @param race - the race who owns the fleets
	 * @return the fleet list for the race
	 */
	public static ArrayList<FleetNode> getFleetList(Race race) {
		ArrayList<FleetNode> list = fleetHashMap.get(race);
		if (list == null) {
			list = new ArrayList<FleetNode>();
			fleetHashMap.put(race, list);
		}
		return list;
	}

	/**
	 * Add the FleetNode to the list of fleets owned by the specified race
	 * 
	 * @param race
	 * @param fleetNode
	 */
	public static void addFleetToRaceList(Race race, FleetNode fleetNode) {
		ArrayList<FleetNode> fleets = GameData.getFleetList(race);
		fleets.add(fleetNode);
	}

	/**
	 * Returns the list of fleets orbiting the specified star.
	 * 
	 * @param starNode - the star where the fleets are orbiting
	 * @return the list of fleets orbiting the star
	 */
	public static ArrayList<FleetNode> getOrbitingFleets(StarNode starNode) {
		ArrayList<FleetNode> list = orbitingHashMap.get(starNode);
		if (list == null) {
			list = new ArrayList<FleetNode>(1);
			orbitingHashMap.put(starNode, list);
		}
		return list;
	}

	/**
	 * Returns the list of fleets departing from the specified star.
	 * 
	 * @param starNode - the star where the fleets are departing from
	 * @return the list of fleets departing the star
	 */
	public static ArrayList<FleetNode> getDepartingFleets(StarNode starNode) {
		ArrayList<FleetNode> list = departingHashMap.get(starNode);
		if (list == null) {
			list = new ArrayList<FleetNode>(1);
			departingHashMap.put(starNode, list);
		}
		return list;
	}

	/**
	 * Add the specified fleet to the discard list.
	 * 
	 * @param fleetNode - the fleet to discard
	 */
	public static void discard(FleetNode fleetNode) {
		discardList.add(fleetNode);
	}

	/**
	 * Clear the fleets in the discarded list by disposing them to the pool.
	 */
	public static void clearDiscardList() {
		for (FleetNode fleetNode : discardList) {
			Race owner = fleetNode.getFleet().owner;
			ArrayList<FleetNode> list = getFleetList(owner);
			list.remove(fleetNode);
			FleetNode.dispose(fleetNode);
		}
		discardList.clear();
	}

}
